#include "gobang.h"
#include <chrono>
#include <iostream>
#include "rclcpp/rclcpp.hpp"
#include "gobang_interfaces/srv/init.hpp"
#include "gobang_interfaces/srv/play.hpp"
#include "gobang_interfaces/srv/suggest.hpp"
#include "gobang_interfaces/msg/game_state_web.hpp"
#include "gobang_interfaces/msg/serial_chess.hpp"
using gobang_interfaces::srv::Init;
using gobang_interfaces::srv::Play;
using gobang_interfaces::srv::Suggest;
using gobang_interfaces::msg::GameStateWeb;
using gobang_interfaces::msg::SerialChess;



class GobangNode : public rclcpp::Node
{
public:
	GobangNode() : rclcpp::Node("gobang_node")
	{
		RCLCPP_INFO(this->get_logger(), "Gobang service is preparing.");
		this->playService = this->create_service<Play>("gobang_play",
															   std::bind(&GobangNode::play_handler, this, std::placeholders::_1, std::placeholders::_2));
		this->initService = this->create_service<Init>("gobang_init",
															   std::bind(&GobangNode::init_handler, this, std::placeholders::_1, std::placeholders::_2));
		this->suggestService = this->create_service<Suggest>("gobang_suggest",
															   std::bind(&GobangNode::suggest_handler, this, std::placeholders::_1, std::placeholders::_2));
		this->gameStateTopicPub = this->create_publisher<gobang_interfaces::msg::GameStateWeb>("gobang_game_state", 10);
		this->serialPub = this->create_publisher<gobang_interfaces::msg::SerialChess>("serial_chess_pub", 10);
		RCLCPP_INFO(this->get_logger(), "Gobang service is ready.");
		this->game = std::make_unique<Gobang>();
		game->printBoard();

	}

private:
	std::unique_ptr<Gobang> game;
	rclcpp::Service<Play>::SharedPtr playService;
	rclcpp::Service<Init>::SharedPtr initService;
	rclcpp::Service<Suggest>::SharedPtr suggestService;
	rclcpp::Publisher<gobang_interfaces::msg::GameStateWeb>::SharedPtr gameStateTopicPub;
	rclcpp::Publisher<gobang_interfaces::msg::SerialChess>::SharedPtr serialPub;
	GameState state;

	void publishGameState(GameState game_state, const std::vector<int8_t> last_move) {
		auto gameStateMsg = GameStateWeb();
		std::vector<unsigned char> board;
		this->game->get1dBoard(board);
		gameStateMsg.board = board;
		gameStateMsg.game_status = static_cast<int8_t>(game_state);
		gameStateMsg.last_move = last_move;
		gameStateTopicPub->publish(gameStateMsg);
	}

	void init_handler(const Init::Request::SharedPtr request, Init::Response::SharedPtr response){
		response->structure_needs_at_least_one_member = 0;
		RCLCPP_INFO(this->get_logger(), "init_handler");
		bool is_first = request->is_first;
		int difficulty = request->difficulty;
		std::vector<int8_t> move = {-1, -1};
		this->game = std::make_unique<Gobang>();
		this->game->setDifficulty(difficulty);
		this->state = GameState::OnGoing;
		if (!is_first) {
			state = game->play(7, 7);
			move = {7, 7};
			game->printBoard();
			auto serialChessMsg = SerialChess();
			serialChessMsg.row = 7;
			serialChessMsg.col = 7;
			this->serialPub->publish(serialChessMsg);
			RCLCPP_INFO(this->get_logger(), "serialChessMsg: row = %d, col = %d", serialChessMsg.row, serialChessMsg.col);
		}
		// 发布当前游戏状态
		publishGameState(state, move);
	}

	void play_handler(const Play::Request::SharedPtr request, Play::Response::SharedPtr response)
	{
		response->structure_needs_at_least_one_member = 0;
		RCLCPP_INFO(this->get_logger(), "play_handler");
		int row = request->row;
		int col = request->col;
		// 悔棋
		if (row == -1 || col == -1)
		{
			game->undo();
			game->undo();
			game->printBoard();
			// 发布当前游戏状态
			publishGameState(GameState::OnGoing, {-1, -1});
			return;
		}
		// 玩家下棋
		state = game->play(row, col);
		game->printBoard();

		if (state != GameState::OnGoing)
		{
			// 发布当前游戏状态
			publishGameState(state, {(int8_t)row, (int8_t)col});
			return;
		}
		// 发布当前游戏状态
		publishGameState(state, {(int8_t)row, (int8_t)col});
		
		// AI 下棋
		auto move = game->bestMove(game->getCurrentPlayer());

		state = game->play(move.first, move.second);
		auto serialChessMsg = SerialChess();
		serialChessMsg.row = move.first;
		serialChessMsg.col = move.second;
		this->serialPub->publish(serialChessMsg);
		RCLCPP_INFO(this->get_logger(), "serialChessMsg: row = %d, col = %d", serialChessMsg.row, serialChessMsg.col);
		game->printBoard();

		if (state != GameState::OnGoing)
		{
			publishGameState(state, {(int8_t)move.first, (int8_t)move.second});
			return;
			
		}
		publishGameState(state, {(int8_t)move.first, (int8_t)move.second});
		return;
	}

	void suggest_handler(const Suggest::Request::SharedPtr request, Suggest::Response::SharedPtr response)
	{
		RCLCPP_INFO(this->get_logger(), "suggest_handler");
		char player = game->getCurrentPlayer();
		
		// 如果use_current_player为false，则为对方玩家提供建议
		if (!request->use_current_player) {
			player = (player == 'O') ? 'X' : 'O';
		}
		
		auto bestPosition = game->bestMove(player);
		response->row = bestPosition.first;
		response->col = bestPosition.second;
		
		RCLCPP_INFO(this->get_logger(), "Suggesting move: (%d, %d) for player %c", 
			response->row, response->col, player);
	}
};

int main(int argc, char **argv)
{
	rclcpp::init(argc, argv);
	auto node = std::make_shared<GobangNode>();
	rclcpp::spin(node);
	rclcpp::shutdown();
}